home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Just Call Me Internet
/
Just Call Me Internet.iso
/
archives
/
com
/
internet
/
stik
/
gls002b5.zoo
/
memdemon.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-09-21
|
8KB
|
324 lines
#include <string.h>
#include <stdlib.h>
#include <osbind.h>
#define DAEMON /* to get "int caller_pid, " */
#include "global.h"
#define POOLSIZE_DEFAULT 50000L
#define POOLSIZE_VAR "ALLOCMEM"
#define MIN_CHUNK (sizeof(chunk_header) + 8)
#define ALLOCED 0xAB000000UL
#define FREED 0xFB000000UL
#define round(n) (((n) + 7) & ~7)
#define is_alloced(H) (((H)->size & 0xFF000000L) == ALLOCED)
#define is_freed(H) (((H)->size & 0xFF000000L) == FREED)
#define chunksize(H) ((H)->size & 0x00FFFFFFL)
typedef struct chunk_header {
struct chunk_header *next;
unsigned long size;
} chunk_header;
static unsigned char *pool = 0;
static unsigned long poolsize = POOLSIZE_DEFAULT;
static chunk_header *arena;
extern int daemon_pid; /* from transdmn.c */
int init_mem(void)
{
register char *s = do_getvstr(daemon_pid, POOLSIZE_VAR);
if (Psem_create(ARENA_SEM) < 0) {
Cconws("Unable to create arena semaphore\r\n");
return 0;
}
/* We own semaphores when they're created; release them so we can
grab them later. */
Psem_release(ARENA_SEM);
if (s)
poolsize = strtoul(s, NULL, 0);
if (poolsize <= MIN_CHUNK) {
Cconws("alloc pool size too small - using default size\r\n");
poolsize = POOLSIZE_DEFAULT;
}
pool = (unsigned char *)Mxalloc(poolsize, 0x2B); /* global, prefer TT RAM */
if (!pool) {
Cconws("Unable to allocate alloc pool\r\n");
return 0;
}
arena = (chunk_header *)pool;
arena->next = 0;
arena->size = (poolsize - sizeof(chunk_header)) | FREED;
return 1;
}
/* join_next() -- Joins chunk |H| with the next block and sets its state to
|state|. WARNING: Assumes |H->next| is not NULL. */
static void join_next(register chunk_header *H, unsigned long state)
{
register chunk_header *H2 = H->next;
H->next = H2->next;
H->size = (chunksize(H) + chunksize(H2) + sizeof(chunk_header)) | state;
}
/* try_split() -- split chunk |block| into two chunks, the first of size
|newsize|, if there's room for a second chunk. The new chunk (if
any) is marked FREED; the (possibly smaller) original block is marked
ALLOCED. WARNING: assumes |newsize| is already round()'ed. */
static void try_split(chunk_header *block, unsigned long newsize)
{
register chunk_header *H;
if (chunksize(block) - newsize >= MIN_CHUNK) {
H = (chunk_header *)((unsigned char *)(block + 1) + newsize);
H->next = block->next;
H->size = (chunksize(block) - newsize - sizeof(chunk_header)) | FREED;
block->next = H;
block->size = newsize | ALLOCED;
/* if the next block is free, merge the new block into it */
if (H->next && is_freed(H->next))
join_next(H, FREED);
} else {
block->size = chunksize(block) | ALLOCED;
}
}
#if 0
extern int caller_pid; /* from transdmn.c */
#endif
char* do_KRmalloc(int caller_pid, int32 size)
{
register chunk_header *H;
size = round(size);
if (size >= 0x01000000L || size == 0) {
#ifdef DEBUG
LOG(caller_pid, DBG_ERROR, "KRmalloc(%l) returns 0", size);
#if 0
debug("sls", "KRmalloc(", size, ") returns 0");
#endif
#endif
return 0;
}
Psem_obtain(ARENA_SEM);
for (H = arena; H; H = H->next) {
if (!is_freed(H) || chunksize(H) < size)
continue;
try_split(H, size);
#ifdef DEBUG
LOG(caller_pid, DBG_SYSCALL, "KRmalloc(%l) returns %p",
size, (void *)(H+1));
#if 0
debug("slsp", "KRmalloc(", size, ") returns ", (void *)(H+1));
#endif
#endif
return (char *)(H + 1);
}
Psem_release(ARENA_SEM);
#ifdef DEBUG
LOG(caller_pid, DBG_ERROR, "KRmalloc(%l) returns 0", size);
#if 0
debug("sls", "KRmalloc(", size, ") returns 0");
#endif
#endif
return 0;
}
void do_KRfree(int caller_pid, void *mem)
{
register chunk_header *H = (chunk_header *)mem;
#ifdef DEBUG
LOG(caller_pid, DBG_SYSCALL, "Entering KRfree(%p)", mem);
#if 0
debug("sps", "in KRfree(", mem, ")");
#endif
#endif
if (!mem)
return;
H--; /* step back to the header */
if (!is_alloced(H)) {
#ifdef DEBUG
LOG(caller_pid, DBG_ERROR,
"In KRfree(%p): block not allocated by KR{m,re}alloc()", mem);
#if 0
debug("s", "\tblock not alloced?");
#endif
#endif
return;
}
H->size = chunksize(H) | FREED;
Psem_obtain(ARENA_SEM);
if (H->next && is_freed(H->next)) {
/* next block is free; merge with it */
join_next(H, FREED);
}
if (H != arena) {
/* there is a previous chunk; merge with it if it's freed */
register chunk_header *H2;
for (H2 = arena; H2 && H2->next != H; H2 = H2->next)
continue;
if (!H2) { /* this shouldn't happen */
#ifdef DEBUG
LOG(caller_pid, DBG_ERROR,
"In KRfree(%p): cannot find block in arena", mem);
#if 0
debug("s", "\tno previous block?");
#endif
#endif
} else {
if (is_freed(H2)) {
join_next(H2, FREED);
H = H2;
}
}
}
Psem_release(ARENA_SEM);
#ifdef DEBUG
LOG(caller_pid, DBG_SYSCALL, "Exiting KRfree(%p)", mem);
#if 0
debug("s", "\tdone");
#endif
#endif
}
int32 do_KRgetfree(int caller_pid, int16 flag)
{
register chunk_header *H;
register unsigned long size = 0;
#ifdef DEBUG
LOG(caller_pid, DBG_SYSCALL, "Entering KRgetfree(%d)", flag);
#if 0
debug("s", "in KRgetfree()");
#endif
#endif
Psem_obtain(ARENA_SEM);
if (flag) {
for (H = arena; H; H = H->next) {
if (is_freed(H) && chunksize(H) > size)
size = chunksize(H);
}
} else {
for (H = arena; H; H = H->next) {
if (is_freed(H))
size += chunksize(H);
}
}
Psem_release(ARENA_SEM);
#ifdef DEBUG
LOG(caller_pid, DBG_SYSCALL, "KRgetfree(%d) returns %l", flag, size);
#endif
return size;
}
char* do_KRrealloc(int caller_pid, char *mem, int32 newsize)
{
register chunk_header *H = (chunk_header *)mem;
#ifdef DEBUG
LOG(caller_pid, DBG_SYSCALL, "Entering KRrealloc(%p, %l)", mem, newsize);
#if 0
debug("s", "in KRrealloc()");
#endif
#endif
if (!mem) {
void *newmem = do_KRmalloc(caller_pid, newsize);
if (newmem)
memset(newmem, 0, newsize);
#ifdef DEBUG
LOG(caller_pid, (mem ? DBG_SYSCALL : DBG_ERROR),
"KRrealloc(%p, %l) returns %p", mem, newsize, newmem);
#endif
return newmem;
}
if (newsize == 0) {
do_KRfree(caller_pid, mem);
#ifdef DEBUG
LOG(caller_pid, DBG_SYSCALL,
"KRrealloc(%p, %l) returns 0", mem, newsize);
#endif
return 0;
}
H--; /* step back to the header */
if (!is_alloced(H))
return 0;
newsize = round(newsize);
if (newsize <= chunksize(H)) {
Psem_obtain(ARENA_SEM);
/* if we're downsizing, we may have room to split the chunk */
try_split(H, newsize);
#ifdef DEBUG
LOG(caller_pid, DBG_SYSCALL,
"KRrealloc(%p, %l) returns %p", mem, newsize, mem);
#endif
return mem;
} else if (H->next && is_freed(H->next) &&
(chunksize(H) + chunksize(H->next) +
sizeof(chunk_header)) >= newsize) {
/* Next chunk is free and big enough to accommodate the new size;
join it with the current chunk */
join_next(H, ALLOCED);
/* We may even have room to split off part of the newly joined chunk */
try_split(H, newsize);
Psem_release(ARENA_SEM);
#ifdef DEBUG
LOG(caller_pid, DBG_SYSCALL,
"KRrealloc(%p, %l) returns %p", mem, newsize, mem);
#endif
return mem;
} else {
register char *newmem = do_KRmalloc(caller_pid, newsize);
if (!newmem) {
#ifdef DEBUG
LOG(caller_pid, DBG_ERROR,
"KRrealloc(%p, %l) returns 0", mem, newsize);
#endif
return 0;
}
memcpy(newmem, mem, chunksize(H));
do_KRfree(caller_pid, mem);
#ifdef DEBUG
LOG(caller_pid, DBG_SYSCALL,
"KRrealloc(%p, %l) returns %p", mem, newsize, newmem);
#endif
return newmem;
}
}
void cleanup_mem()
{
if (pool) Mfree(pool);
}